package com.xyy.saas.payment.adpater.aliPayHandler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.xyy.framework.redis.core.RedisClient;
import com.xyy.saas.payment.adpater.channel.setting.ChannelSettingManager;
import com.xyy.saas.payment.common.exception.PaymentException;
import com.xyy.saas.payment.cores.bo.PayBo;
import com.xyy.saas.payment.cores.bo.TransactionResultBO;
import com.xyy.saas.payment.cores.enums.PayModeEnum;
import com.xyy.saas.payment.cores.enums.ResultCodeEnum;
import com.xyy.saas.payment.cores.enums.TransactionStatusEnum;
import com.xyy.saas.payment.cores.param.TransactionParam;
import com.xyy.saas.payment.dao.model.AlipaySettings;
import com.xyy.saas.payment.dao.model.RefundOrder;
import com.xyy.saas.payment.payment.core.dto.PayDto;
import com.xyy.saas.payment.payment.core.service.RefundOrderService;
import com.xyy.saas.payment.util.AmountCastUtil;
import com.xyy.saas.payment.util.ApolloUtil;
import com.xyy.saas.payment.util.DateUtil;
import com.xyy.saas.payment.util.JSONUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Date;

/**
 * @Author zhangwenxiong
 * @Date 2020/12/1 11:08
 * @Version 1.0
 */
@Component
public class AliQrPayHandler implements AliPayChannelHandler {
    private static final Logger LOGGER = LoggerFactory.getLogger(AliQrPayHandler.class);

    @Autowired
    private RedisClient redisClient;

    @Autowired
    private ChannelSettingManager channelSettingManager;

    @Autowired
    private RefundOrderService refundOrderService;

    @Override
    public String getMethod() {
        return PayModeEnum.QR.getMode();
    }

    @Override
    public PayBo pay(PayDto payDto) throws PaymentException {
        PayBo appPayBo = redisClient.get(payDto.getPayMode()+payDto.getPayNo()+"aliqr", PayBo.class);
        if(appPayBo != null) {
            LOGGER.info("AliQrPayHandler pay end get from redis appPayBo:{}", JSON.toJSONString(appPayBo));
            return appPayBo;
        }
        AlipayClient client = channelSettingManager.getAlipayClient(payDto.getReceiverId(), payDto.getBusinessOrderType(), payDto.getPayMode());
        LOGGER.info("AliQrPayHandler pay begin payDto:{}",JSON.toJSONString(payDto));
        PayBo payBo = new PayBo();
        //获取请求体
        AlipayTradePrecreateRequest alipayRequest =  new  AlipayTradePrecreateRequest();
        AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
        model.setOutTradeNo(payDto.getPayNo());
        model.setTotalAmount(new BigDecimal(payDto.getAmount()).divide(new BigDecimal(100),2,BigDecimal.ROUND_UNNECESSARY).toString());
        model.setSubject(payDto.getSubject());
        model.setTimeoutExpress(payDto.getMap().get("timeoutExpress") == null? null:payDto.getMap().get("timeoutExpress").toString());
        model.setBody(payDto.getBody());
        alipayRequest.setNotifyUrl(ApolloUtil.getProperty("alipay.notifyUrl.pay.direct"));
        alipayRequest.setBizModel(model);
        //调用支付宝接口
        try {
            AlipayTradePrecreateResponse response = client.execute(alipayRequest);
            if (!"10000".equals(response.getCode())){
                LOGGER.error("AliQrPayHandler pay ali error payNo:{}, code:{}, msg:{}", payDto.getPayNo(), response.getCode(), response.getMsg());
                throw new PaymentException(ResultCodeEnum.CHANNEL_CONNECT_ERROR.getCode(), ResultCodeEnum.CHANNEL_CONNECT_ERROR.getMsg());
            }

            //获取返回的二维码
            String trade_no = response.getQrCode();
            payBo.setPayLoad(trade_no);
            payBo.setPayNO(payDto.getPayNo());
            LOGGER.info("AliQrPayHandler pay end PayNo:{}", payDto.getPayNo());
        } catch (AlipayApiException e) {
            LOGGER.error("AliQrPayHandler pay ali error payNo:{}, exception:{}", payDto.getPayNo(),e);
            throw new PaymentException(ResultCodeEnum.CHANNEL_CONNECT_ERROR.getCode(), ResultCodeEnum.CHANNEL_CONNECT_ERROR.getMsg());
        }
        //默认超时时间,如果业务有传超时时间就按照他们的时间+5400秒
        Integer expire = 5400;
        if (null != payDto.getTimeExpire() && payDto.getTimeExpire().after(new Date())) {
            expire = DateUtil.getSecondsFromToday(payDto.getTimeExpire()).intValue() + expire;
        }
        redisClient.set(payDto.getPayMode() + payDto.getPayNo() + "aliqr", payBo,expire);
        return payBo;
    }

    @Override
    public TransactionResultBO queryPay(TransactionParam param) throws PaymentException {
        LOGGER.info("AliAppPayHandler queryPay begin param:{}", JSONUtils.toJSON(param));
        AlipayClient client = channelSettingManager.getAlipayClient(param.getAccountId(), param.getBusinessOrderType(), param.getPayMode());
        AlipaySettings alipaySettings = channelSettingManager.getAlipaySettings(param.getAccountId(), param.getBusinessOrderType(), param.getPayMode());
        if (null == client){
            throw new PaymentException(ResultCodeEnum.DEFAULT_ERROR);
        }
        //获取请求体
        AlipayTradeQueryRequest alipayRequest = new AlipayTradeQueryRequest();
        TransactionResultBO resultBO = new TransactionResultBO();
        resultBO.setMerchantId(alipaySettings.getAlipayAppId());
        //开始组装支付宝APP接口需要的参数
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(param.getTradeNo());
        alipayRequest.setBizModel(model);
        //返回支付宝订单信息(预处理)
        try {
            AlipayTradeQueryResponse response = client.execute(alipayRequest);
            if(response.isSuccess()){
                resultBO.setTradeNo(param.getTradeNo());
                resultBO.setAmount(AmountCastUtil.castYuan2Fen(response.getTotalAmount()));
                resultBO.setChannelChargeNo(response.getTradeNo());
                switch (response.getTradeStatus()) {
                    case "TRADE_SUCCESS":
                        resultBO.setStatus(TransactionStatusEnum.SUCCESS.getCode());
                        resultBO.setSuccessTime(DateUtil.dateToLong(response.getSendPayDate()));
                        break;
                    case "WAIT_BUYER_PAY":
                        resultBO.setStatus(TransactionStatusEnum.TRANSACTING.getCode());
                        break;
                    default:
                        resultBO.setStatus(TransactionStatusEnum.TRANSACTING.getCode());
                        break;
                }
                return resultBO;
            }
            throw new PaymentException(ResultCodeEnum.CHANNEL_CONNECT_ERROR,response.getMsg());
        } catch (AlipayApiException e) {
            throw new PaymentException(ResultCodeEnum.CHANNEL_CONNECT_ERROR.getCode());
        } catch (Exception e) {
            throw new PaymentException(ResultCodeEnum.DEFAULT_ERROR);
        }
    }

    @Override
    public TransactionResultBO queryRefund(TransactionParam param) throws PaymentException {
        LOGGER.info("AliAppPayHandler queryPay begin param:{}", JSONUtils.toJSON(param));
        AlipayClient client = channelSettingManager.getAlipayClient(param.getAccountId(), param.getBusinessOrderType(), param.getPayMode());
        if (null == client){
            throw new PaymentException(ResultCodeEnum.DEFAULT_ERROR);
        }

        RefundOrder refundOrder = refundOrderService.selectByRefundNo(param.getTradeNo());
        if(null == refundOrder) {
            throw new PaymentException(ResultCodeEnum.TRADE_NOT_EXIT_ERROR);
        }
        TransactionResultBO resultBO = new TransactionResultBO();
        resultBO.setTradeNo(param.getTradeNo());

        AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest();
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", refundOrder.getPayNo());
        bizContent.put("out_request_no", refundOrder.getRefundNo());
        request.setBizContent(bizContent.toString());

        try {
            AlipayTradeFastpayRefundQueryResponse response = client.execute(request);
            if(response.isSuccess()){
                resultBO.setChannelChargeNo(response.getTradeNo());
                resultBO.setSuccessTime(DateUtil.dateToLong(response.getGmtRefundPay()));
                resultBO.setAmount(AmountCastUtil.castYuan2Fen(response.getRefundAmount()));
                if("REFUND_SUCCESS".equals(response.getRefundStatus())) {
                    resultBO.setStatus(TransactionStatusEnum.SUCCESS.getCode());
                }else{
                    resultBO.setStatus(TransactionStatusEnum.FAIL.getCode());
                }
                return resultBO;
            } else {
                resultBO.setStatus(TransactionStatusEnum.TRANSACTING.getCode());
                return resultBO;
            }
        } catch (AlipayApiException e) {
            throw new PaymentException(ResultCodeEnum.CHANNEL_CONNECT_ERROR.getCode());
        } catch (Exception e) {
            throw new PaymentException(ResultCodeEnum.DEFAULT_ERROR);
        }
    }
}
